/*
 * @Author: Fan Dong
 * @Date: 2021-06-25 17:22:37
 * @LastEditors: Fan Dong
 * @LastEditTime: 2021-06-30 11:13:40
 * @Description: 文件描述
 * @FilePath: \learn-typescript\ts\6.接口.ts
 */

/*

分类：
  属性接口
  函数类型接口
  可索引接口
  类型接口
  接口扩展

  
接口的作用：在面向对象编程中，接口是一种规范的定义，它定义了行为和动作的规范，在程序设计里面，接口起到一种限制和规范的作用，
接口定义了某一批类所需要的遵守的规范，接口不关心这些类的内部状态数据，也不关心这些类里面方法的实现细节，它只规定了这批类里必须提供某些方法，
提供这些方法的类就可以满足实际需要，ts中的接口类似于java，同事还增加了更灵活的接口类型，包括属性、函数、可索引和类等。

定义标准


*/

// 1、属性接口  对json的约束

/*
// ts中定义方法
function printLable(): void {
  console.log('printLable')
}
printLable();
*/

/*

// ts中定义方法传入参数
function printLable(label: string): void {
  console.log("printLable");
}
printLable('hahha')

*/

/*

// ts中自定义传入参数对json进行约束
function printLable(lableInfo: { label: string }): void {
  console.log("printLable");
}
// printLable('jaja') //错误
// printLable(123) //错误
// printLable({name:'张三'}) //错误
printLable({ label: "哈哈哈骄傲"}); //正确

*/

// 对批量方法传入参数进行约束
// 接口，行为和动作的规范，对批量方法进行约束

/*
// 就是传入对象的约束   属性的接口
interface FullName {
  firstName: string; //注意分号结束
  secondName: string;
}

function printName(name: FullName) {
  // 必须传入对象 firstName secondName
  console.log(name.firstName + "--" + name.secondName);
}

// printName({age:10,firstName:'李',secondName:'明'}) // 报错
// printName({firstName:'李',secondName:'明'}) // 正确
let obj = {
  //传入的参数必须包含firstName和secondName
  age: 10,
  firstName: "李",
  secondName: "明",
};

printName(obj)

*/

/*
interface FullName {
  firstName: string; //注意分号结束
  secondName: string;
}

function printName(name: FullName) {
  // 必须传入对象 firstName secondName
  console.log(name.firstName + "--" + name.secondName);
}

function printInfo(info: FullName) {
  // 必须传入对象 firstName secondName
  // console.log(info.firstName + "--" + info.secondName + info.age); // 报错
  console.log(info.firstName + "--" + info.secondName);
}

let obj = {
  //传入的参数必须包含firstName和secondName
  age: 10,
  firstName: "李",
  secondName: "明",
};

let info = {
  //传入的参数必须只包含firstName和secondName
  // age: 10,
  firstName: "李",
  secondName: "四",
};

printName(obj);
printInfo(info);

*/

/*

// 接口：可选属性

interface FullName {
  firstName: string; //注意分号结束
  secondName?: string;
}
function getName(name: FullName) {
  console.log(name);
}

// 参数顺序可以不一样
getName({
  // secondName: "secondName",
  firstName: "firstName",
});

*/

/*
// 2、函数类型接口：对方法传入的参数 以及返回值进行约束  批量约束

interface encrypt {
  (key: string, value: string): string;
}

let md5: encrypt = function (key: string, value: string): string {
  return key + value;
};

let sha1: encrypt = function (key: string, value: string): string {
  return key + "---" + value;
};
console.log(md5("name", "张三"));
console.log(sha1("name", "李四"));

*/

// 3、可索引接口：数组、对象的约束（不常用）

/*

// 可索引接口：对数组的约束

// ts中定义数组的方式
// let arr11: number[] = [245, 567];

// let arr22: Array<string> = ["123", "456"];


interface UserArr{
  [index: number]:string
  // [index: number]:any
}

let arr33: UserArr=['aaa','bbb'];
// let arr33: UserArr=[123,'bbb']; // 错误
console.log(arr33[0])

*/

/*
// 可索引接口：对对象的约束
interface UserObj {
  [index: string]: string;
}

let arrr: UserObj = { name: "张三" }; //  正确
// let arrr: UserObj = { name: "张三", age: "20" }; //  正确
// let arrr: UserObj = { name: "张三", age: 20 }; // 错误


*/

//4、类类型接口：对类的约束 和 抽象类有点相似
interface Animal2 {
  name: string;
  eat(str: string): void;
}

class Dog2 implements Animal2 {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  eat() {
    console.log(this.name + "吃粮食");
  }
}
let d = new Dog2("小黑");
d.eat();

class Cat2 implements Animal2 {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  eat(food: string) {
    console.log(this.name + "吃" + food);
  }
}

let c = new Cat2("小花");
c.eat("老鼠");

//5、接口的扩展：接口可以继承接口

/*
interface Animal3 {
  eat(): void;
}

interface Person3 extends Animal3 {
  work(): void;
}
class Web3 implements Person3 {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  work() {
    console.log(this.name + "爱写代码");
  }
  eat() {
    console.log(this.name + "爱吃鱼");
  }
}

let w3 = new Web3("李丽");

w3.work();
w3.eat();

*/

interface Animal4 {
  eat(): void;
}

interface Person4 extends Animal4 {
  work(): void;
}

class Programmer {
  name: string;
  constructor(name: string) {
    this.name = name;
  }

  coding(code: string) {
    console.log(this.name + code);
  }
}

class Web4 extends Programmer implements Person4 {
  constructor(name: string) {
    super(name);
  }
  eat() {
    console.log(this.name + "喜欢吃馒头");
  }
  work() {
    console.log(this.name + "写代码");
  }
}

let w4 = new Web4("小李");
w4.eat();
w4.work();
w4.coding('写ts代码');
